/**
 * 前面给一些类型定义，后面查询指定变量名的类型
 * 类型分两类：
 * 1 基础类型：int，double
 * 2 pair类型：形如 pair<TypeA,TypeB>
 * 问变量的类型或者变量.first或者second的类型
 * 
 * 变量名本身用map记录即可
 * 每一种类型用三元组表示
 * struct _t{
 *      名字
 *      first类型
 *      second类型
 * } 
 * 名字即字符串格式的名字，也就是输出的内容
 * 后面跟first与second类型，基础类型此成员域为空
 * 定义语句，扫描的时候递归处理即可。
 * 输入保证了只有一个空格，且格式正确
 */
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;

using llt = long long;
using vi = vector<int>;
using vll = vector<llt>;
using pii = pair<int, int>;
using pll = pair<llt, llt>;

struct _t{
    string name;
    int first;
    int second;
};

vi Left2Right;
map<string, int> Hash;
vector<_t> Type;
map<string, int> Var;

int N, Q;

int dfs(const string & s, int left, int right){
    if('i' == s[left]){
        assert(right - left + 1 == 3);
        return 1;
    }
    if('d' == s[left]){
        assert(right - left + 1 == 6);
        return 2;
    }

    assert('p' == s[left]);
    auto it = Hash.find(s.substr(left, right - left + 1));
    if(it != Hash.end()) return it->second;

    int a = left + 5;
    int b = 0;
    int x = 0, y = 0;
    if('i' == s[a]){
        x = 1;
        b = a + 4; 
    }else if('d' == s[a]){
        x = 2;
        b = a + 7;
    }else if('p' == s[a]){
        int tmp = Left2Right[a];
        assert(tmp);
        x = dfs(s, a, tmp);
        b = tmp + 2;
    }else{
        assert(0);
    }

    y = dfs(s, b, right - 1);
    assert(x and y);
    it = Hash.insert(it, {s.substr(left, right - left + 1), Type.size()});
    Type.emplace_back(_t{s.substr(left, right - left + 1), x, y});
    return it->second;    
}

int procType(const string & s){
    Left2Right.assign(s.length(), 0);
    vi st;
    for(int i=0,n=s.length();i<n;++i){
        if('p' == s[i]){
            st.emplace_back(i);
        }else if('>' == s[i]){
            Left2Right[st.back()] = i;
            st.pop_back();
        }
    }

    return dfs(s, 0, s.length() - 1);
}

void proc(const string & s){
    auto t = s.find(' ');
    int type = procType(s.substr(0, t));
    auto it = Var.find(s.substr(t + 1));
    assert(it == Var.end());
    Var.insert(it, {s.substr(t + 1), type});
    return;
}

void answer(const string & s){
    auto t = s.find('.');
    if(string::npos == t){
        auto it = Var.find(s);
        assert(it != Var.end());
        cout << Type[it->second].name << "\n";
        return;
    }

    auto it = Var.find(s.substr(0, t));
    assert(it != Var.end());
    int cur = it->second;

    while(1){
        if('f' == s[t + 1]){
            cur = Type[cur].first;
        }else if('s' == s[t + 1]){
            cur = Type[cur].second;
        }else{
            assert(0);
        }
        t = s.find('.', t + 1);
        if(string::npos == t) break;
    }

    cout << Type[cur].name << "\n";
    return;
}

void work(){
    Type.reserve(2000000);
    Type.emplace_back(_t{});
    Type.emplace_back(_t{"int", 0, 0});
    Type.emplace_back(_t{"double", 0, 0});
    Hash["int"] = 1;
    Hash["double"] = 2;

    cin >> N >> Q;
    string s; getline(cin, s);
    for(int i=1;i<=N;++i){
        getline(cin, s);
        assert(s.back() == ';');
        s.pop_back();
        proc(s);
    }
    for(int q=1;q<=Q;++q){
        getline(cin, s);
        answer(s);
    }
    return;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);	
    int nofkase = 1;
	// cin >> nofkase;
	while(nofkase--) work();
	return 0;
}